package sysService

import (
	"fmt"
	"gitee.com/jokces/kit/errc"
	"gitee.com/jokces/kit/gen/str"
	"gitee.com/jokces/kit/global"
	sysModel "gitee.com/jokces/kit/global/admin/model"
	"gitee.com/jokces/kit/logs"
	"gitee.com/jokces/kit/typ"
	"go.uber.org/zap"
	"time"
)

// SendSmsCode 发送短信验证码
func (svc *Service) SendSmsCode(mobile, randCode string) error {
	mobile = typ.GlobalMobile(mobile)
	code := str.RandNumCode(4)
	if global.GetCfg().Msg.IsMock {
		code = "0000"
	}
	if err := svc.codeToCache(mobile, randCode, sysModel.MessageSmsCodeTtl, code); err != nil {
		return err
	}

	bizInfo := "0000"
	sendStatus := 1
	if !global.GetCfg().Msg.IsMock {
		if success, msg, err := svc.s.SendSingleCode(mobile, code); err != nil {
			bizInfo = msg
			sendStatus = 2
		} else if success {
			bizInfo = msg
		}
	}
	rs := sysModel.MessageRecords{
		ToUser:     mobile,
		Content:    code,
		RandCode:   randCode,
		BizCode:    sysModel.Code,
		MsgType:    sysModel.MsgTypeSms,
		SendTime:   time.Now().Unix(),
		BizInfo:    bizInfo,
		SendStatus: int32(sendStatus),
	}
	if _, err := global.GetDb().InsertOne(rs); err != nil {
		logs.Qezap.Error("【发送短信】 保存记录异常", zap.Any("email", mobile), zap.Error(err))
		return errc.ErrInternalErr.MultiMsg("短信发送失败")
	}
	return nil
}
func (svc *Service) VerifySmsCode(mobile, randCode, code string, del bool) (bool, error) {
	mobile = typ.GlobalMobile(mobile)
	return svc.verifyCode(mobile, randCode, code, sysModel.MessageSmsCodeTtl, del)
}

// SendEmailCode 发送邮件验证码的处理
func (svc *Service) SendEmailCode(email, randCode string) error {
	code := str.RandNumCode(4)
	if global.GetCfg().Msg.IsMock {
		code = "0000"
	}
	sub, temp := global.GetCfg().Msg.FindTemp(sysModel.Code)
	content := fmt.Sprintf(temp, code)

	if err := svc.codeToCache(email, randCode, sysModel.MessageEmailCodeTtl, code); err != nil {
		return err
	}

	go func() {
		bizInfo := "0000"
		sendStatus := 1
		if !global.GetCfg().Msg.IsMock {
			if _, err := svc.s.SendText(sub, content, email); err != nil {
				sendStatus = 2
				bizInfo = err.Error()
				logs.Qezap.Error("【发送邮件】", zap.Any("email", email), zap.Error(err))
			}
		}
		rs := sysModel.MessageRecords{
			ToUser:     email,
			Content:    content,
			RandCode:   randCode,
			BizCode:    sysModel.Code,
			MsgType:    sysModel.MsgTypeEmail,
			SendTime:   time.Now().Unix(),
			BizInfo:    bizInfo,
			SendStatus: int32(sendStatus),
		}
		if _, err := global.GetDb().InsertOne(rs); err != nil {
			logs.Qezap.Error("【发送邮件】 保存记录异常", zap.Any("email", email), zap.Error(err))
		}
	}()
	return nil
}
func (svc *Service) VerifyCode(email, randCode, code string, del bool) (bool, error) {
	return svc.verifyCode(email, randCode, code, sysModel.MessageEmailCodeTtl, del)
}

func (svc *Service) codeToCache(to, randCode, keyTyp, code string) error {
	key := fmt.Sprintf("%v:%v:%v", keyTyp, to, randCode)
	keyIncr := fmt.Sprintf("%v:%v:%v", keyTyp, to, sysModel.MessageMax)
	//这里需要检查
	if global.GetCfg().Msg.MaxDay > 0 {
		_, count, err := global.GetRedis().IncrGet(keyIncr)
		if err != nil {
			return err
		}
		if count+1 > global.GetCfg().Msg.MaxDay {
			return errc.ErrInternalErr.MultiMsg("最大次数超限!")
		}
	}

	//存储
	if ok, err := svc.r.SaveOrGetByJson(key, code, false, 30*time.Minute); err != nil {
		return err
	} else if !ok {
		return errc.ErrInternalErr.MultiMsg("发送失败")
	}

	//加入次数
	err := svc.r.IncrInt64(keyIncr, 1, 24*time.Hour)
	if err != nil {
		return err
	}
	return nil
}
func (svc *Service) verifyCode(email, randCode, code, keyTyp string, del bool) (bool, error) {
	key := fmt.Sprintf("%v:%v:%v", keyTyp, email, randCode)
	val := ""
	if _, err := svc.r.SaveOrGetByJson(key, &val, true, 0); err != nil {
		return false, err
	}

	if val != "" && del {
		_ = svc.r.ClearFixedKey(key)
	}
	return val == code, nil
}
